package com.javaxiaobear.base.common.utils.job;

import com.javaxiaobear.base.common.utils.StringUtils;
import com.javaxiaobear.base.common.utils.spring.SpringUtils;
import com.javaxiaobear.module.monitor.domain.SysJob;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.LinkedList;
import java.util.List;

/**
 * 任务执行工具
 *
 * @author javaxiaobear
 */
public class JobInvokeUtil {
  /**
   * 执行方法
   *
   * @param sysJob 系统任务
   */
  public static void invokeMethod(SysJob sysJob) throws Exception {
    String invokeTarget = sysJob.getInvokeTarget();
    String beanName = getBeanName(invokeTarget);
    String methodName = getMethodName(invokeTarget);
    List<Object[]> methodParams = getMethodParams(invokeTarget);

    if (!isValidClassName(beanName)) {
      Object bean = SpringUtils.getBean(beanName);
      invokeMethod(bean, methodName, methodParams);
    } else {
      Object bean = Class.forName(beanName).getDeclaredConstructor().newInstance();
      invokeMethod(bean, methodName, methodParams);
    }
  }

  /**
   * 调用任务方法
   *
   * @param bean 目标对象
   * @param methodName 方法名称
   * @param methodParams 方法参数
   */
  private static void invokeMethod(Object bean, String methodName, List<Object[]> methodParams)
      throws NoSuchMethodException,
          SecurityException,
          IllegalAccessException,
          IllegalArgumentException,
          InvocationTargetException {
    if (StringUtils.isNotNull(methodParams) && !methodParams.isEmpty()) {
      Method method = bean.getClass().getMethod(methodName, getMethodParamsType(methodParams));
      method.invoke(bean, getMethodParamsValue(methodParams));
    } else {
      Method method = bean.getClass().getMethod(methodName);
      method.invoke(bean);
    }
  }

  /**
   * 校验是否为为class包名
   *
   * @param invokeTarget 名称
   * @return true是 false否
   */
  public static boolean isValidClassName(String invokeTarget) {
    return StringUtils.countMatches(invokeTarget, ".") > 1;
  }

  /**
   * 获取bean名称
   *
   * @param invokeTarget 目标字符串
   * @return bean名称
   */
  public static String getBeanName(String invokeTarget) {
    String beanName = StringUtils.substringBefore(invokeTarget, "(");
    return StringUtils.substringBeforeLast(beanName, ".");
  }

  /**
   * 获取bean方法
   *
   * @param invokeTarget 目标字符串
   * @return method方法
   */
  public static String getMethodName(String invokeTarget) {
    String methodName = StringUtils.substringBefore(invokeTarget, "(");
    return StringUtils.substringAfterLast(methodName, ".");
  }

  /**
   * 获取method方法参数相关列表
   *
   * @param invokeTarget 目标字符串
   * @return method方法相关参数列表
   */
  public static List<Object[]> getMethodParams(String invokeTarget) {
    String methodStr = StringUtils.substringBetween(invokeTarget, "(", ")");
    if (StringUtils.isEmpty(methodStr)) {
      return null;
    }
    String[] methodParams = methodStr.split(",(?=([^\"']*[\"'][^\"']*[\"'])*[^\"']*$)");
    List<Object[]> classs = new LinkedList<>();
    for (String methodParam : methodParams) {
      String str = StringUtils.trimToEmpty(methodParam);
      // String字符串类型，以'或"开头
      if (StringUtils.startsWithAny(str, "'", "\"")) {
        classs.add(new Object[] {StringUtils.substring(str, 1, str.length() - 1), String.class});
      }
      // boolean布尔类型，等于true或者false
      else if ("true".equalsIgnoreCase(str) || "false".equalsIgnoreCase(str)) {
        classs.add(new Object[] {Boolean.valueOf(str), Boolean.class});
      }
      // long长整形，以L结尾
      else if (StringUtils.endsWith(str, "L")) {
        classs.add(
            new Object[] {
              Long.valueOf(StringUtils.substring(str, 0, str.length() - 1)), Long.class
            });
      }
      // double浮点类型，以D结尾
      else if (StringUtils.endsWith(str, "D")) {
        classs.add(
            new Object[] {
              Double.valueOf(StringUtils.substring(str, 0, str.length() - 1)), Double.class
            });
      }
      // 其他类型归类为整形
      else {
        classs.add(new Object[] {Integer.valueOf(str), Integer.class});
      }
    }
    return classs;
  }

  /**
   * 获取参数类型
   *
   * @param methodParams 参数相关列表
   * @return 参数类型列表
   */
  public static Class<?>[] getMethodParamsType(List<Object[]> methodParams) {
    Class<?>[] classs = new Class<?>[methodParams.size()];
    int index = 0;
    for (Object[] os : methodParams) {
      classs[index] = (Class<?>) os[1];
      index++;
    }
    return classs;
  }

  /**
   * 获取参数值
   *
   * @param methodParams 参数相关列表
   * @return 参数值列表
   */
  public static Object[] getMethodParamsValue(List<Object[]> methodParams) {
    Object[] classs = new Object[methodParams.size()];
    int index = 0;
    for (Object[] os : methodParams) {
      classs[index] = os[0];
      index++;
    }
    return classs;
  }
}
